package com.soccertgc.data.enum
{
	import com.soccertgc.utils.ClassUtils;
	
	import flash.utils.Dictionary;
	
	public class Enum
	{
		
		// -------------------------------------------------------------------------------
		// STATIC FIELDS
		// -------------------------------------------------------------------------------
		
		// private static var _init:Boolean = false;
		// protected static var _list:Vector.<Enum> = new Vector.<Enum>;
		
		// Enums metadata
		private static var _enums:Dictionary = new Dictionary(true);
		
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		private var _id:int;
		private var _name:String;
		private var _description:String;
		private var _class:String;
		private var _className:String;
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTORS
		// -------------------------------------------------------------------------------
		
		public function Enum(id:int, name:String, description:String)
		{
			// Store the class path and class name
			_class = ClassUtils.getPath(this);
			_className = _class.split("::")[1];
			// Safe unique instance lock
			if (isInit(_class)) throw new Error(_className + " enum already created!");
			// Init
			_id    		 = id;
			_name  		 = name;
			_description = description;
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------              
		
		public function get id():int
		{
			return _id;
		}
		
		public function get name():String
		{
			return _name;
		}
		
		public function get description():String
		{
			return _description;
		}
		
		protected function get UID():String
		{
			return _class;
		}
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
		
		public function toString():String
		{
			return _className + "::" + _name;
		}
		
		// -------------------------------------------------------------------------------
		// STATIC METHODS
		// -------------------------------------------------------------------------------
		
		/**
		 * Initialize the enumerator.
		 * For internal use only, call inside private static constructor 
		 * @param items Items to register in the enumerator
		 */		
		protected static function init(items:Array):void
		{
			// Items check
			if (items == null) throw new Error("Enum items list should not be null!");
			if (items.length <= 1) throw new Error("Enum items list should cointains more than 1 element!");
			// Retrieve the enum fll class path used as unique id for registration
			var enumClass:String  = ClassUtils.getPath(items[0]);
			// Check if the enum is already initialized and registered
			if (isInit(enumClass)) throw new Error(enumClass + " enum already created!");
			// Creates the metadata for enumerator and register 
			_enums[enumClass] = new EnumMetadata(items);
		}
		
		/**
		 * Returns the metatata for the 
		 * @return 
		 */		
		protected static function getMetadata(uid:String):EnumMetadata
		{
			// Check if the enum is already initialized and registered
			if (!isInit(uid)) throw new Error(uid + " enum does not exists!");
			// Retrieve metadata
			return _enums[uid];
		}
		
		/**
		 * Check if and enumerator is initialized, verifiing if the enum metatada is registered 
		 * @param enumClass
		 * @return True if the enum for the given class path exists and is registered
		 */		
		public static function isInit(uid:String):Boolean
		{
			return _enums.hasOwnProperty(uid);
		}
		
		/**
		 * Returns the list of the names of enumerator items 
		 * @return List of the names of the game sides
		 */
		public static function names(uid:String):Array
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Output items list
			var list:Array  = new Array();
			// Loop over values list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				list.push(metadata.items[i].name);
			}
			return list;
		}
		
		/**
		 * Returns the list of enumerator items
		 * @return 
		 */
		public static function list(uid:String):Array
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Output items list
			var list:Array = new Array();
			// Loop over values list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				list.push(metadata.items[i]);
			}
			return list;
		}
		
		/**
		 * Search an enum item by given id 
		 * @param id Id of the log target to find
		 * @return  Enum item for the given id
		 */             
		public static function getById(uid:String, id:int):Enum
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Search the value into the list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				if (metadata.items[i].id == id) return metadata.items[i];
			}
			throw new Error(uid + " enum item for id '" + id + "' not found!");
		}
		
		/**
		 * Search an enum item by given name 
		 * @param name Name of the enum item to find
		 * @return Enum item for the given name
		 */             
		public static function getByName(uid:String, name:String):Enum
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Search the value into the list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				if (metadata.items[i].name == name) return metadata.items[i];
			}
			throw new Error(uid + " enum item for name '" + name + "' not found!");
		}
		
		/**
		 * Search an enum item by given description 
		 * @param description Description of the enum item to find
		 * @return Enum item for the given description
		 */        
		public static function getByDescription(uid:String, description:String):Enum
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Search the value into the list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				if (metadata.items[i].description == description) return metadata.items[i];
			}
			throw new Error(uid + " enum item for description '" + description + "' not found!");
		}

		/**
		 * Search an enum item by given property name 
		 * @param name Name of the property to use to search the enum item
		 * @param value Value of the property of the enum item to find
		 * @return Enum item for the given property value
		 */
		public static function getByProperty(uid:String, name:String, value:String):Enum
		{
			// Retrieves metadata
			var metadata:EnumMetadata = getMetadata(uid);
			// Search the value into the list
			for (var i:int=0; i<metadata.items.length; i++)
			{
				if (metadata.items[i][name].toString() == value) return metadata.items[i];
			}
			throw new Error(uid + " enum item for " + name + " '" + value + "' not found!");
		}
		
	}
}